// 柯里化函数
// 默认指定的函数参数与传入回调函数决定
function curry(callback: Function, paramNum = callback.length) {
  // 内部的curry函数
  // --->真正的柯里化逻辑写在这里
  /** 参数列表
   * @param fn    原函数
   * @param len   所需的参数个数长度
   * @param args  已接收的参数列表（真正调用前会保存下来）
   */
  const _curry = function (fn: Function, len: number, ...args: any[]) {
    return function (...params: any[]) {
      let totalParams = [...args, ...params]; // 总维护的参数列表
      if (totalParams.length >= len) {
        return fn.apply(null, totalParams);// 达到参数长度后调用
      } else {
        return _curry(fn, len, ...totalParams);// 未达到参数长度，储存下当前的参数长度并返回闭包函数
      }
    };
  };
  return _curry(callback, paramNum);// 返回柯里函数
}


// 测试用例 ---> 输出值函数
function logValue(...params: any[]) {
  console.log(...params);
}
const curry_logValue = curry(logValue, 5);// 五个参数个数则自动运算
curry_logValue(1, 2, 3, 4, 5);// 输出1、2、3、4、5
curry_logValue(1)(2, 3)(4, 5);// 输出1、2、3、4、5
// curry_logValue(2)(2,3)(4,5)(6,7);// 报错

// 定参数个数的组合函数
// --->接受两个函数
function doubleCompose(f: Function, g: Function) {
  return function (param: any) {
    return g(f(param));
  };
}

// --->接受三个参数
function tribleCompose(f: Function, g: Function, m: Function) {
  return function (param: any) {
    return m(g(f(param)));
  };
}

// 不定参数的组合函数
function composition(...callbacks: Function[]) {
  return function (params: any) {
    return callbacks.reduce((acc: any, curr: any) => {
      return curr(acc);
    }, params)
  }
}

// 测试用例
// 字符串大写函数
function UpperStr(str:string){
  return str.toUpperCase();
}
// 字符串倒置函数
function reverseStr(str:string){
  return str.split("").reverse().join("");
}
// 截取前5个字符的函数
function getFirstFiveLetter(str:string){
  return str.slice(0,5);
}
// 现在需要让字符全部大写并倒置最后取前5个字符
const upperReverseThree = composition(UpperStr,reverseStr,getFirstFiveLetter);// 得到组合函数
console.log(upperReverseThree('hello function programing'));// GNIMA
// 现在需要让字符全部大写并倒置
const upperReverse = composition(UpperStr,reverseStr);// 得到组合函数
console.log(upperReverse('hello function programing'));// GNIMARGORP NOITCNUF OLLEH